home *** CD-ROM | disk | FTP | other *** search
- /* ***** BEGIN LICENSE BLOCK *****
- *
- * Pearltrees add-on AMO, Copyright(C), 2009, Broceliand SAS, Paris, France
- * (company in charge of developing Pearltrees)
- *
- * This file is part of ΓÇ£Pearltrees add-on AMOΓÇ¥.
- *
- * Pearltrees add-on AMO is free software: you can redistribute it and/or modify it under the
- * terms of the GNU General Public License version 3 as published by the Free Software Foundation.
- *
- * Pearltrees add-on AMO is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with Pearltrees add-on AMO.
- * If not, see <http://www.gnu.org/licenses/>
- *
- * ***** END LICENSE BLOCK ***** */
-
- /////////////////////////////////////////////////////////////////////////////////
- // Model class
- // Handle server connections and password managers
- //
- // Classes:
- //
- // BRO_model Communication with the server
- // BRO_JSON Handle JSON objects
- //
- /////////////////////////////////////////////////////////////////////////////////
-
- /**
- * Communication with the server.
- */
- var BRO_model = {
-
- _json:null,
- _serviceUrl:null,
-
- _treeList:null, // treeItem: treeID, title, pearlCount, lastUpdate
- _historyList:null, // historyItem: id, name, pearlCount, lastUpdate
- _currentUser:null, // user: userID, userDB, username, rootTreeID
-
- _skipNotificationIfNotLoggedOnNextValidation:false,
-
- getServiceUrl: function(){return this._serviceUrl},
-
- getTreeList: function(){return this._treeList},
- setTreeList: function(value){this._treeList = value},
-
- getHistoryList: function(){return this._historyList},
- setHistoryList: function(value){this._historyList = value},
-
- getCurrentUser: function(){return this._currentUser},
- setCurrentUser: function(value){this._currentUser = value},
-
- getRootTree: function () {
- if(!this._treeList || !this._currentUser) return null;
-
- var treeListLength = this._treeList.length;
-
- for (var i = 0; i < treeListLength; i++) {
- if (this._treeList[i].treeID == this._currentUser.rootTreeID) {
- return this._treeList[i];
- }
- }
- return null;
- },
-
- START_HISTORY_SUCCESS:0,
- START_HISTORY_SUCCESS_ON_SWITCH:1,
- START_HISTORY_ERROR_INVALID_TREE:2,
- START_HISTORY_ERROR_TREE_DELETED:3,
- START_HISTORY_ERROR_IS_NOT_OWNER:4,
-
- skipNextRequestValidation:false,
-
- /**
- * Init server connection parameters
- * @todo Should be moved in a config file
- */
- init: function() {
- this._treeList = null;
- this._historyList = null;
- this._currentUser = null;
- this._serviceUrl = BRO_SERVICE_FF_URL;
-
- // Try to use FF3 native json component
- if(Components.classes["@mozilla.org/dom/json;1"]) {
- this._json = Components.classes["@mozilla.org/dom/json;1"]
- .createInstance(Components.interfaces.nsIJSON);
- }else{
- this._json = JSONFF2;
- }
- },
-
- /**
- * Create a GET XMLHttpRequest object with a valid cookie.
- * @param string url
- * @return XMLHttpRequest
- */
- createXMLHttpRequest:function(url) {
- var req = new XMLHttpRequest();
- req.open('GET', url, true);
-
- return req;
- },
-
- notifyDownloadToAMO:function() {
- var url = BRO_AMO_FILE_URL + "?src=" + BRO_AMO_SOURCE;
-
- var req = this.createXMLHttpRequest(url);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- BRO_toolbar.onDownloadNotifiedToAMO();
- }
- }
- req.send(null);
- },
-
- notifyActiveUserToAMO:function() {
- var extension = Components.classes["@mozilla.org/extensions/manager;1"]
- .getService(Components.interfaces.nsIExtensionManager)
- .getItemForID(BRO_ADDON_ID);
- var appInfo = Components.classes["@mozilla.org/xre/app-info;1"]
- .getService(Components.interfaces.nsIXULAppInfo);
- var xulRuntime = Components.classes["@mozilla.org/xre/app-info;1"]
- .getService(Components.interfaces.nsIXULRuntime);
- var useragentPrefs = Components.classes["@mozilla.org/preferences-service;1"]
- .getService(Components.interfaces.nsIPrefService)
- .getBranch("general.useragent.");
-
- var reqVersion = "%"; // request last version
- var version = extension.version; // current addon version (e.g: 5.0.9)
- var id = extension.id; // addon id (e.g: collector@broceliand.fr)
- var appID = appInfo.ID; // Firefox Application ID
- var appVersion = appInfo.version; // Firefox version (e.g: 3.6b4)
- var locale = useragentPrefs.getCharPref("locale"); // lang (e.g: en_US)
- var appOS = xulRuntime.OS; // OS family (e.g: WINNT)
- var appABI = xulRuntime.XPCOMABI; // compiler info
- var maxAppVersion = extension.maxAppVersion; // addon max version supported
- var status = "userEnabled"; // is the addon enabled
- if(typeof(Application) != 'undefined') {
- var extensions = Application.extensions.all;
- for(var i=0; i<extensions.length; i++) {
- var ext = extensions[i];
- if(ext.id == id) {
- status = (ext.enabled)?"userEnabled":"userDisabled";
- }
- }
- }
-
- var url = BRO_AMO_VERSION_CHECK +
- "?reqVersion="+reqVersion+
- "&version="+version+
- "&id="+id+
- "&appID="+appID+
- "&appVersion="+appVersion+
- "&locale="+locale+
- "&appOS="+appOS+
- "&appABI="+appABI+
- "&maxAppVersion="+maxAppVersion+
- "&status="+status;
-
- var req = this.createXMLHttpRequest(url);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- BRO_toolbar.onActiveUserNotifiedToAMO();
- }
- }
- req.send(null);
- },
-
- /**
- * Start a new history
- */
- start:function(newTreeName) {
- var action = 'start';
- var params = '?newTreeName='+newTreeName
- +'&time='+BRO_tools.getTime();
-
- BRO_log.log('start new history ('+newTreeName+')');
-
- var req = this.createXMLHttpRequest(this._serviceUrl+action+params);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- if(BRO_model.validateResponse(req,true)) {
- if(req.responseText) {
- //BRO_log.log('Started !'+req.responseText);
- }
- }
- };}
- req.send(null);
- },
-
- /**
- * continue an existing history
- */
- continueHistory:function(treeID, historyID) {
- var action = 'continue';
- var params = '?time='+BRO_tools.getTime()
- +'&treeID='+treeID
- +'&historyID='+historyID;
-
- BRO_log.log('continue history ('+treeID+', '+historyID+')');
-
- var req = this.createXMLHttpRequest(this._serviceUrl+action+params);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- if(BRO_model.validateResponse(req,true) && req.responseText) {
- if(req.responseText == BRO_model.START_HISTORY_ERROR_TREE_DELETED) {
- BRO_toolbar.showTreeDeletedMessage();
- }else if(req.responseText != BRO_model.START_HISTORY_SUCCESS) {
- BRO_toolbar.errorOnContinueHistory(req.responseText);
- }
- }
- };}
- req.send(null);
- },
-
- addComment:function(url, browserUID, time, comment) {
-
- var action = 'addcomment';
- var params = '?url='+encodeURIComponent(url)
- +'&browserUID='+browserUID
- +'&time='+time
- +'&comment='+comment;
-
- BRO_log.log('add comment ('+url+', '+browserUID+', '+time+', '+comment+')');
-
- var req = this.createXMLHttpRequest(this._serviceUrl+action+params);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- BRO_model.validateResponse(req,true);
- };}
- req.send(null);
- },
-
- /**
- * Add a new pearl
- */
- add:function(url, title, method, browserUID, time, isStart, treeID, newTreeName, historyID) {
- var action = 'add';
- var title = encodeURIComponent(title.replace(/^\s*|\s*$/g,''));
- var treeID = (!isStart && BRO_inButtonController._selectedTree)?BRO_inButtonController._selectedTree.treeID:null;
- var historyID = (!isStart && BRO_inButtonController._selectedHistory)?BRO_inButtonController._selectedHistory.id:null;
-
- var params = '?url='+encodeURIComponent(url)
- +'&title='+title
- +'&method='+method
- +'&browserUID='+browserUID
- +'&time='+time;
- if(isStart) {
- params += '&isStart='+isStart;
- params += '&newTreeName='+newTreeName;
- }
- if(treeID) params += '&treeID='+treeID;
- if(historyID) params += '&historyID='+historyID;
-
- // If the method sent will create a pearl we run an effect
- // @todo run the effect on server response
- if(method != BRO_METHOD_TAB_CREATED) {
- BRO_buttonEffectHelper.runIsRecordingEffect();
- }
-
- BRO_log.log('add ('+url+', '+title+', '+method+' , '+browserUID+ ', '+time+', '+isStart+', '+treeID+', '+newTreeName+', '+historyID+')');
-
- var req = this.createXMLHttpRequest(this._serviceUrl+action+params);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- if(BRO_model.validateResponse(req,true) && req.responseText) {
- // If recording in a deleted tree
- if(req.responseText == BRO_model.START_HISTORY_ERROR_TREE_DELETED) {
- BRO_toolbar.showTreeDeletedMessage();
- }
- // If a server error occured
- else if(req.responseText != BRO_model.START_HISTORY_SUCCESS && req.responseText != BRO_model.START_HISTORY_SUCCESS_ON_SWITCH) {
- BRO_toolbar.errorOnContinueHistory(req.responseText);
- }
- }
- };}
- req.send(null);
- },
-
- /**
- * Validate URLs for inserts
- * @param string url
- */
- isValidUrl:function(url) {
- if(!url
- || url == ''
- || url == 'about:blank'
- || url.lastIndexOf(BRO_PUBLIC_URL) == 0
- || url.lastIndexOf('http://www.broceliand.fr') ==0
- || (url.lastIndexOf('http://www.pearltrees.com') ==0
- && url.lastIndexOf('http://www.pearltrees.com/blog') == -1
- && url.lastIndexOf('http://www.pearltrees.com/forum') == -1)
- || url.lastIndexOf('http://localhost') ==0
- || url.lastIndexOf('http://127.0.0.1') ==0
- || url.substring(0,4) != 'http'){
- return false;
- }
- return true;
- },
-
- /**
- * Clear the current history if exist.
- * Called when the application stop.
- */
- clear:function() {
- var action = 'clear';
- var params = '?time='+BRO_tools.getTime();
-
- BRO_log.log('clear');
-
- var req = this.createXMLHttpRequest(this._serviceUrl+action+params);
-
- req.onreadystatechange = function (e) {
- if (e && e.readyState == 4) {
- //...
- };
- }
- req.send(null);
- },
-
- getTreesAndCurrentUser:function(skipNotificationIfNotLogged) {
- var action = 'gettreesandcurrentuser';
- var params = '';
-
- this._skipNotificationIfNotLoggedOnNextValidation = skipNotificationIfNotLogged;
- BRO_log.log('load trees and current user');
-
- var req = this.createXMLHttpRequest(this._serviceUrl+action+params);
-
- req.onreadystatechange = function (e) {
- if (req.readyState == 4) {
- if(BRO_model.validateResponse(req)) {
- if (req.responseText) {
- var response = BRO_model._json.decode(req.responseText);
-
- var currentUserResponse = response.currentUser;
- BRO_model.updateCurrentUser(currentUserResponse);
-
- var listChanged = false;
- var treeListResponse = response.treeList;
- var historyListResponse = response.historyList;
-
- if(!BRO_model._treeList || !BRO_model.areTreeListsEquals(treeListResponse,BRO_model._treeList)) {
- BRO_model._treeList = BRO_model.mergeLocalTreeListWithServerList(treeListResponse);
- BRO_windowManager.setTreeList(BRO_model._treeList);
- // must be called after currentUser being set
- BRO_toolbar.saveRootTreeIntoPreferences(BRO_model.getRootTreeFromTreeList());
- BRO_toolbar.saveDropZoneIntoPreferences(BRO_model.getDropZoneFromTreeList());
- listChanged = true;
- }
-
- if(!BRO_model._historyList || !BRO_model.areHistoryListsEquals(historyListResponse,BRO_model._historyList)) {
- BRO_model._historyList = BRO_model.mergeLocalHistoryListWithServerList(historyListResponse);
- BRO_windowManager.setHistoryList(BRO_model._historyList);
- listChanged = true;
- }
-
- if(listChanged) {
- BRO_inButtonController.onTreeListLoaded();
- }
- else{
- BRO_inButtonController.onTreeListNotChanged();
- }
- }
- }
- }
- }
- req.send(null);
- },
-
- getRootTreeFromTreeList:function() {
- var treeList = BRO_model.getTreeList();
- var currentUser = BRO_model.getCurrentUser();
- if(!treeList || !currentUser) return;
-
- for(var i=0; i < treeList.length; i++) {
- if(treeList[i].treeID == currentUser.rootTreeID) {
- return treeList[i];
- }
- }
- return null;
- },
-
- getDropZoneFromTreeList:function() {
- var treeList = BRO_model.getTreeList();
- var currentUser = BRO_model.getCurrentUser();
- if(!treeList || !currentUser) return;
-
- for(var i=0; i < treeList.length; i++) {
- if(treeList[i].treeID == currentUser.dropZoneID) {
- return treeList[i];
- }
- }
- return null;
- },
-
- updateCurrentUser:function(value) {
- if(!BRO_model.areUserEquals(value, BRO_model._currentUser)) {
- BRO_model._currentUser = value;
- BRO_windowManager.setCurrentUser(BRO_model._currentUser);
- if(BRO_model._currentUser) {
- BRO_toolbar.saveCurrentUserIntoPreferences(BRO_model._currentUser);
- }
- }
- if(BRO_toolbar.getOptionWindow() && BRO_toolbar.getOptionWindow().document) {
- var statusDescription = BRO_toolbar.getOptionWindow().document.getElementById('BRO_statusDescription');
- if(statusDescription) {
- if(BRO_toolbar.isUserLogged && BRO_model._currentUser) {
- statusDescription.value = "signed as "+BRO_model._currentUser.username;
- }else{
- statusDescription.value = "signed out";
- }
- }
- }
- },
-
- areTreeListsEquals:function(list1, list2) {
- if(!list1 && !list2) return true;
- if((!list1 && list2) || (list1 && !list2)) return false;
- var list1Length = list1.length;
- var list2Length = list2.length;
- if(list1Length != list2Length) return false;
-
- for(var i=0; i < list1Length;i++) {
- if(list1[i].treeID != list2[i].treeID) {
- return false;
- }
- else if(list1[i].title != list2[i].title) {
- return false;
- }
- else if(list1[i].lastUpdate != list2[i].lastUpdate) {
- return false;
- }
- }
- return true;
- },
-
- mergeLocalTreeListWithServerList:function(serverTreeList) {
- var localTreeList = BRO_model._treeList;
-
- if(!localTreeList) return serverTreeList;
- if(!serverTreeList) return null;
- var serverTreeListLength = serverTreeList.length;
- var localTreeListLength = localTreeList.length;
-
- // Don't update trees if we don't need to
- for(var i=0; i < serverTreeListLength; i++) {
- for(var j=0; j < localTreeListLength; j++) {
- if(serverTreeList[i].treeID == localTreeList[j].treeID
- && serverTreeList[i].title == localTreeList[j].title
- && serverTreeList[i].lastUpdate == localTreeList[j].lastUpdate) {
-
- serverTreeList[i] = localTreeList[j];
- break;
- }
- }
- }
-
- return serverTreeList;
- },
-
- mergeLocalHistoryListWithServerList:function(serverHistoryList) {
- var localHistoryList = BRO_model._treeList;
-
- if(!localHistoryList) return serverHistoryList;
- if(!serverHistoryList) return null;
- var serverHistoryListLength = serverHistoryList.length;
- var localHistoryListLength = localHistoryList.length;
-
- // Don't update trees if we don't need to
- for(var i=0; i < serverHistoryListLength; i++) {
- for(var j=0; j < localHistoryListLength; j++) {
- if(serverHistoryList[i].id == localHistoryList[j].id
- && serverHistoryList[i].name == localHistoryList[j].name
- && serverHistoryList[i].lastUpdate == localHistoryList[j].lastUpdate) {
-
- serverHistoryList[i] = localHistoryList[j];
- break;
- }
- }
- }
-
- return serverHistoryList;
- },
-
- areHistoryListsEquals:function(list1, list2) {
- if(!list1 && !list2) return true;
- if((!list1 && list2) || (list1 && !list2)) return false;
- var list1Length = list1.length;
- var list2Length = list2.length;
- if(list1Length != list2Length) return false;
-
- for(var i=0; i < list1Length;i++) {
- if(list1[i].id != list2[i].id || list1[i].name != list2[i].name) return false;
- }
- return true;
- },
-
- areUserEquals:function(user1, user2) {
- if(!user1 && !user2) return true;
- if((!user1 && user2) || (user1 && !user2)) return false;
- return (user1.userID == user2.userID)?true:false;
- },
-
- /**
- * Validate XMLHttpRequest reponse and handle errors
- * @param resp XMLHttpRequest response
- */
- validateResponse:function(resp, retryOnError) {
- if(!resp) return false;
- var status = null;
- var responseText = null;
- try{
- status = resp.status;
- responseText = resp.responseText;
- }
- catch(e){}
-
- // Valid
- if(status == 200 || this.skipNextRequestValidation) {
- this.skipNextRequestValidation = false;
- BRO_toolbar.isUserLogged = true;
- return true;
- }
- // No session auth is opened.
- else if(status == 303) {
- BRO_log.log("server 303 Not Logged");
- BRO_toolbar.isUserLogged = false;
- // Stop all recording actions.
- BRO_toolbar.setRecording(false);
- if(!BRO_toolbar.isThirdPartyCookiesEnabled()) {
- if(BRO_toolbar.isUserWantToEnableThirdPartyCookies()){
- BRO_toolbar.enableThirdPartyCookies();
- if(retryOnError) BRO_ButtonsHandler.startRecording();
- }
- }
- else if(!this._skipNotificationIfNotLoggedOnNextValidation) {
- if(BRO_toolbar.isUserWantToLogin()==true) {
- BRO_toolbar.showLoginForm();
- }
- }
- BRO_model.resetModel();
- }
- // Unauthorized WWW-Authenticate
- else if(status == 401){
- if(BRO_toolbar.isRecording) {
- BRO_toolbar.setRecording(false);
- }
- }
- else {
- BRO_log.log("Invalid server response. HTTP status: "+status+" "+responseText);
- BRO_log.error(BRO_locale.getString('popup.error.responseError'));
- }
- this.skipNextRequestValidation = false;
- return false;
- },
-
- // @todo refactor
- resetModel:function() {
- // update model
- BRO_model.updateCurrentUser(null);
-
- BRO_model.setTreeList(null);
- BRO_windowManager.setTreeList(null);
-
- BRO_model.setHistoryList(null);
- BRO_windowManager.setHistoryList(null);
-
- // update toolbar state
- BRO_toolbar.setRecording(false);
-
- // update ButtonsHandler
- BRO_inButtonController._selectedTree = null;
- BRO_inButtonController._selectedHistory = null;
- BRO_inButtonController._selectedNewHistory = null;
-
- BRO_inButtonController.initTreeList();
- BRO_toolbar.lastUrlRecorded = null;
- BRO_recordButtonController.refreshRecordButtonLabel(BRO_toolbar.isRecording);
- }
- }